;-----------------------------------------
; This file is part of Fresh standard
; macro library.
;-----------------------------------------

..FastEnter = 0
..ShowSkipped = 1
..CheckArguments = 0


macro locals {
  local ..locsize
  locsize equ ..locsize
  virtual at ebp - ..locsize - .__info.commonframe
  @@:
}

macro endl {
  rb (4 - ($- @b) and 11b) and 11b
  locsize = $ - @b
  if $-@b > maxsize
    maxsize = $-@b
  end if
  end virtual
  restore locsize
}


macro errendp {
  end if
  Missing 'endp' or 'endwp' before the procedure.
}


macro proc name, [arg] {
  common
    macro errendp#open@proc _%sc sc%_
    errendp
    purge  errendp#open@proc
    open@proc fix inside

    if ~ used name
      if ..ShowSkipped
        display 1,'Procedure skiped: ',`name, $0d, $0a
      end if
    else

  name:
    .__info.id = 1

    virtual at ebp+8
      if ~ arg eq
  forward
        arg dd ?
        if ~ defined name#arg
          ERROR! the argument `arg MUST begins with dot
        end if
  common
      end if
      .__info.argsize = $-ebp-8
    end virtual

  virtual at ebp - .__info.commonframe
  @@:
}

cproc fix proc


macro begin {
    rb (4 - ($ - @b) and 11b) and 11b
    .__info.commonframe = $ - @b
  end virtual

  local ..maxsize
  maxsize equ ..maxsize
  ..maxsize = 0

  if .__info.frame
    if ..FastEnter
      push ebp
      mov  ebp, esp
      sub  esp, .__info.frame
    else
      enter .__info.frame, 0
    end if
  else
    if .__info.argsize
      push ebp
      mov  ebp, esp
    end if
  end if
}


macro cret {
  if .__info.argsize | .__info.frame
    if ..FastEnter
      mov   esp, ebp
      pop   ebp
    else
      leave
    end if
  end if
  retn
}


macro return {
  if .__info.argsize | .__info.frame
    if ..FastEnter
      mov   esp, ebp
      pop   ebp
    else
      leave
    end if
  end if

  if .__info.argsize
    retn .__info.argsize
  else
    retn
  end if
}



macro endp {
    .__info.frame = maxsize + .__info.commonframe
  end if
  restore maxsize
  closeproc
}



macro winproc name, [arg] {
common
  macro errendp#open@proc _%sc sc%_
  errendp
  purge  errendp#open@proc

  open@proc fix inside

  if ~ used name
    if ~ ..ShowSkipped
      display 1,'Message procedure skiped: ',`name, $0d, $0a
    end if
  else
 name:
    .__info.id = 2

  if arg eq
    virtual at ebp+8
      .hwnd dd ?
      .wmsg dd ?
      .wparam dd ?
      .lparam dd ?
      .__info.argsize = 16
    end virtual
  else
    virtual at ebp+8
forward
      arg dd ?
      if ~ defined name#arg
        ERROR! the argument `arg MUST begin with dot
      end if
common
    .__info.argsize = $ - ebp - 8
    end virtual
  end if

  if .__info.argsize <> 16
    Error! The count of `name arguments MUST be 4 dwords.
  end if

    virtual at ebp - .__info.commonframe
    @@:
}



macro ondefault {  ; begins procedure instructions
  common
    local ..msgcounter, ..msglist
    msgcounter equ ..msgcounter
    msglist equ ..msglist

    ..msgcounter = 0

    call JumpTo
    ..msglist:
    rd   .__info.msgcount
    dd   0

    .ondefault:
}


macro onmessage message {
  .#message:
  .#message#.__info.id = 3
  .#message#.__info.number = msgcounter / 4
     store word message at (msglist + msgcounter)
     store word ($ - msglist - msgcounter - 4 ) at (msglist + msgcounter + 2)
  msgcounter = msgcounter + 4
}


macro endwp {
    .__info.msgcount = msgcounter / 4
    .__info.frame = maxsize + .__info.commonframe
  end if
  restore maxsize, msgcounter, msglist
  closeproc
}

macro initialize procname{
  ..INIT@CHAIN fix ..INIT@CHAIN, procname
  proc procname
}

macro finalize procname{
  ..FINISH@CHAIN fix procname, ..FINISH@CHAIN
  proc procname
}

macro callchain [arg] {
forward
  if ~arg eq
      call arg
  end if
}

macro InitializeAll {
  callchain ..INIT@CHAIN
}

macro FinalizeAll {
  callchain ..FINISH@CHAIN
}

..INIT@CHAIN fix
..FINISH@CHAIN fix



;*****************************************
; Call macroses
;*****************************************

macro stdcall proc, [arg] {    ; call procedure
common
  local ..argsize
  ..argsize = 0
  if ~ arg eq
reverse
    pushd arg
    ..argsize = ..argsize + 4
common
  end if
  if ..CheckArguments
    if (defined proc#.__info.argsize) & (proc#.__info.argsize <> ..argsize)
      ERROR! wrong argument count for procedure call.
    end if
  end if

  call proc
}


macro invoke proc,[arg] {   ; invoke procedure (indirect)
common
  if ~ arg eq
reverse
    pushd arg
common
  end if
  call [proc]
}


macro ccall proc,[arg]                  ; call procedure in C calling convention
 { common local ..size
   ..size = 0
   reverse
   pushd arg
   ..size = ..size+4
   common
   call proc
   add esp,..size }

macro cinvoke proc,[arg]                ; invoke procedure (indirect)
 { common
    if ~ arg eq
     ccall [proc],arg
    else
     call [proc]
    end if }


;****************************************
; INT3 break point, when first = second.
;****************************************

macro BreakEq first, second {
  local .lbl
  push  eax
  mov   eax, first
  cmp   eax, second
  pop   eax
  jne   .lbl

  int3

.lbl:
}


_%sc fix {
sc%_ fix }

macro closeproc {
  open@proc fix
}

closeproc
